package rhc.common.commons;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ThreadUtil {

	/**
	 * 线程池保持最小线程数
	 */
	private static final int MIN_THREAD=2;
	
	/**
	 * 线程池保持最大线程数
	 */
	private static final int MAX_THREAD=100;
	
	/**
	 * 使用线程时必须先取得信号，防止大量线程进入导致内存溢出
	 */
	private Semaphore semaphere=new Semaphore(MAX_THREAD);
	
	private static final Logger logger=LoggerFactory.getLogger(ThreadUtil.class);
	
	/**
	 * 
	 */
	protected final ExecutorService asyncTaskExecutor= new ThreadPoolExecutor(MIN_THREAD, MAX_THREAD, 3,  
            TimeUnit.HOURS, new ArrayBlockingQueue<Runnable>(MAX_THREAD),  
            new ThreadPoolExecutor.DiscardOldestPolicy());
	
	/**执行一个线程
	 * @param run
	 * @throws InterruptedException
	 */
	public void async(final Runnable run) throws InterruptedException{
		
		try {
			semaphere.acquire();
		} catch (InterruptedException e) {
			logger.error("运行线程前获取信号输出 {}",e.getMessage());
			throw e;
		}
		asyncTaskExecutor.execute(new Runnable(){
			@Override
			public void run() {
				try{
					run.run();
				}finally{
					semaphere.release();
				}
			}
		});
	}
	
	/**提交一个任务，并返回一个能获取到任务结果的容器
	 * @param call
	 * @return
	 * @throws InterruptedException
	 */
	public <T> Future<T> submitTack(final Callable<T> call) throws InterruptedException{
		
		try {
			semaphere.acquire();
		} catch (InterruptedException e) {
			logger.error("运行线程前获取信号输出 {}",e.getMessage());
			throw e;
		}
		Future<T> result=asyncTaskExecutor.submit(new Callable<T>(){

			@Override
			public T call() throws Exception {
				
				T result=null;
				
				try{
					result=call.call();
				}finally{
					semaphere.release();
				}
				
				return result;
			}
			
		});
		
		return result;
	}
}
